package cn.bingoo.card;

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;

import org.jooq.impl.Factory;
import org.jooq.util.h2.H2Factory;
import org.joou.ULong;

import cn.bingoo.h2.domain.Tables;
import cn.bingoo.h2.domain.tables.records.VouchercardRecord;

/*
CREATE TABLE "BINGOO-HANDY".PUBLIC.VOUCHERCARD (
    CODE VARCHAR(100) NOT NULL,
    HMAC VARCHAR(100) NOT NULL,
    
    PASS VARCHAR(100) NOT NULL,
    CONSTRAINT VOUCHERCARD_PK PRIMARY KEY (CODE)
);

CREATE INDEX VOUCHERCARD_PASS_IDX ON "BINGOO-HANDY".PUBLIC.VOUCHERCARD (PASS);
CREATE INDEX VOUCHERCARD_HMAC_IDX ON "BINGOO-HANDY".PUBLIC.VOUCHERCARD (HMAC);

 */
public class CardMain {
    public static void main(String[] args) throws Exception {
        createVoucherCards();
        checkHMac();
    }

    public static void checkHMac() throws Exception {

        String data = "96476956932751933375";
        String hmmac = "GAG2lV8LlaNJWi70XcBXOw==";
        String hmacKey = "m6Q/cxFzRCulGXmOxn2mg+3snHJi/QJeOIRhNg9RAftpd+FWKmAp6YD1LtECYU8G3xZzzxyfdqesPpnhML1A4A==";

        SecretKey secretKey = new SecretKeySpec(DatatypeConverter.parseBase64Binary(hmacKey), KEY_MAC);
        Mac mac = Mac.getInstance(secretKey.getAlgorithm());
        mac.init(secretKey);

        byte[] ret = mac.doFinal(getUTF8Bytes(data));
        String printBase64Binary = DatatypeConverter.printBase64Binary(ret);
        System.out.println(printBase64Binary.equals(hmmac));

    }

    private static void createVoucherCards() throws SQLException, NoSuchAlgorithmException, InvalidKeyException {
        SecureRandom secureRandom = new SecureRandom();
        DriverManager.registerDriver(new org.h2.Driver());
        Connection conn = DriverManager.getConnection("jdbc:h2:~/bingoo-handy", "sa", "");

        Factory create = new H2Factory(conn);
        KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_MAC);
        SecretKey secretKey = keyGenerator.generateKey();

        String strHmacKey = DatatypeConverter.printBase64Binary(secretKey.getEncoded());
        System.out.println(strHmacKey);

        Mac mac = Mac.getInstance(secretKey.getAlgorithm());
        mac.init(secretKey);

        for (int i = 0; i < 100000; ++i) {
            long firstPart = secureRandom.nextLong();
            long secondPart = secureRandom.nextLong();

            String pass = align(10, firstPart) + align(10, secondPart);
            VouchercardRecord newRecord = create.newRecord(Tables.VOUCHERCARD);
            newRecord.setCode("" + i);
            newRecord.setPass(insertBlanks(pass));
            byte[] ret = mac.doFinal(getUTF8Bytes(pass));
            String hmac = DatatypeConverter.printBase64Binary(ret);

            newRecord.setHmac(hmac);

            newRecord.store();

            if (i % 10000 == 0) {
                System.out.println(i / 10000);
                System.out.println(System.currentTimeMillis());
            }

        }
    }

    private static String insertBlanks(String pass) {
        StringBuilder stringBuilder = new StringBuilder(23);
        stringBuilder.append(pass.substring(0, 5));
        stringBuilder.append(' ');
        stringBuilder.append(pass.substring(5, 10));
        stringBuilder.append(' ');
        stringBuilder.append(pass.substring(10, 15));
        stringBuilder.append(' ');
        stringBuilder.append(pass.substring(15, 20));
        return stringBuilder.toString();
    }

    public static String align(int len, long num) {
        ULong unum = new ULong(num);

        String str = unum.toString();
        if (str.length() > 10) {
            return str.substring(0, 10);
        }

        int paddingZeros = len - str.length();
        StringBuilder sb = new StringBuilder(len);
        while (paddingZeros-- > 0) {
            sb.append('0');
        }
        sb.append(str);
        return sb.toString();

    }

    /** 
     * MAC算法可选以下多种算法 
     *  
     * <pre> 
     * HmacMD5  
     * HmacSHA1  
     * HmacSHA256  
     * HmacSHA384  
     * HmacSHA512 
     * </pre> 
     */
    public static final String KEY_MAC = "HmacMD5";

    /**
     * 取得字符串UTF-8编码字节数组.
     * @param str
     * @return
     */
    public static byte[] getUTF8Bytes(String str) {
        try {
            return str.getBytes("UTF-8");
        }
        catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 生成UTF-8字符串.
     * @param bytes
     * @return
     */
    public static String newUTF8String(byte[] bytes) {
        try {
            return new String(bytes, "UTF-8");
        }
        catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }
}
